package ms.unicorn.dsl.impl;

import ms.unicorn.dsl.IBorderEx;
import ms.unicorn.dsl.IModelLanguage;
import ms.unicorn.dsl.ITheme;
import ms.unicorn.dsl.runtime.ExecutionContext;
import ms.unicorn.dsl.unicornDSL.NamedProperty;
import ms.unicorn.dsl.unicornDSL.impl.ThemeImpl;

import org.eclipse.draw2d.Border;
import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.ConnectionLocator;
import org.eclipse.draw2d.RotatableDecoration;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;

public class Theme extends ThemeImpl implements ITheme {
	private Theme parent;
	private Color foreColor = ColorConstants.black, bkColor = ColorConstants.white, shadowColor = ColorConstants.black;
	private int bkAlpha = 255, shadowAlpha = 128;
	private int corner = 10;
	private Boolean shadow = false;
	private IModelLanguage language;
	private float linewidth = 1;
	private int linetype = SWT.LINE_SOLID;
	private boolean initialized = false;
	private Border border;
	private int lineSmoothness = 0; // SMOOTH_NORMAL
	private int bendpointRadius = 5;
	private Class<RotatableDecoration> targetDecor;
	private Class<RotatableDecoration> sourceDecor;
	private Class<ConnectionLocator> targetDecorLocator;
	private Class<ConnectionLocator> sourceDecorLocator;
	
	public static Theme DEFAULT = new Theme(true);
	
	public Theme() {
		
	}
	
	protected Theme(boolean initialized) {
		this.initialized = initialized;
	}
	
	public IModelLanguage getLanguage() {
		if (language == null) {
			for (EObject lang = this.eContainer(); lang != null; lang = lang.eContainer())
				if (lang instanceof ModelLanguage) 
					return language = (IModelLanguage)lang;
		}
		return language;
	}
	
	@SuppressWarnings({ "unchecked" })
	public <T> T getElementProperty(String name, T defvalue, ExecutionContext context) {
		
		for (EObject eprop: this.getProperties()) 
			if (eprop instanceof NamedProperty) {
				NamedProperty prop = (NamedProperty) eprop;
				if (prop.getName().equalsIgnoreCase(name)) {
					Object value = getLanguage().evaluate(prop.getValue(), context);
					if (Float.class.isInstance(defvalue))
						if (value instanceof Integer)
							return (T)Float.valueOf(((Integer)value).floatValue());
					return (T)value;
				}
			}
		return defvalue;
	}
	
	public <T> T getElementProperty(String name, T defvalue) {
		return getElementProperty(name, defvalue, getLanguage().getContext());
	}
	
	public Theme(Theme parent) {
		this.parent = parent;
	}
	
	protected void init() {
		if (!initialized) {
			initialized = true;
			parent = (Theme) super.getInheritance();
			if (parent == null && this.eContainer instanceof Theme)
				parent = (Theme) this.eContainer;
			if (parent == null)
				parent = DEFAULT;
			foreColor = getElementProperty("color", null);
			bkColor = getElementProperty("background", null);
			shadowColor  = getElementProperty("shadow.color", null);
			bkAlpha = getElementProperty("background.alpha", -1);
			shadowAlpha = getElementProperty("shadow.alpha", -1);
			corner = getElementProperty("roundcorner", -1);
			shadow = getElementProperty("shadow", null);
			linewidth = getElementProperty("linewidth", -1.0f);
			linetype = getElementProperty("linetype", -1);
			lineSmoothness = getElementProperty("smoothness", -1);
			bendpointRadius = getElementProperty("bendpoint.radius", -1);
			this.border = getElementProperty("border", null);
			this.targetDecor = getElementProperty("decoration.target", null);
			this.sourceDecor = getElementProperty("decoration.source", null);
			this.targetDecorLocator = getElementProperty("decoration.target.locator", null);
			this.sourceDecorLocator = getElementProperty("decoration.source.locator", null);
		}
	}
	
	@Override
	public Theme getInheritance() {
		init();
		return parent;
	}
	
	public Color getForeColor() {
		init();
		return foreColor != null ? foreColor : getInheritance() != null ? getInheritance().getForeColor() : null;
	}
	
	public void setForeColor(Color foreColor) {
		this.foreColor = foreColor;
	}
	
	public Color getBackgroundColor() {
		init();
		return bkColor != null ? bkColor : getInheritance() != null ? getInheritance().getBackgroundColor() : null;
	}
	
	public void setBackgroundColor(Color bkColor) {
		init();
		this.bkColor = bkColor;
	}
	
	public Color getShadowColor() {
		init();
		return shadowColor != null ? shadowColor : getParent().getShadowColor();
	}
	
	public void setShadowColor(Color shadowColor) {
		this.shadowColor = shadowColor;
	}
	
	public int getBackgroundAlpha() {
		init();
		return bkAlpha >= 0? bkAlpha : getParent().getBackgroundAlpha();
	}
	
	public void setBackgroundAlpha(int bkAlpha) {
		this.bkAlpha = bkAlpha;
	}
	
	public int getShadowAlpha() {
		init();
		return shadowAlpha >=0 ? shadowAlpha : getParent().getShadowAlpha();
	}
	
	public void setShadowAlpha(int shadowAlpha) {
		this.shadowAlpha = shadowAlpha;
	}
		
	public boolean isShadow() {
		init();
		return shadow != null ? shadow : getInheritance() != null ? getInheritance().isShadow() : null;
	}
	
	public void setShadow(boolean shadow) {
		this.shadow = shadow;
	}

	public Theme getParent() {
		return parent;
	}

	public void setParent(Theme parent) {
		this.parent = parent;
	}

	@Override
	public Border getBorder() {
		init();
		return this.border != null ? border : getParent() != null ? getParent().getBorder() : null;
	}

	@Override
	public int getRoundCorner() {
		init();
		return corner > 0? corner : getParent().getRoundCorner();
	}

	@Override
	public float getLineWidth() {
		init();
		return linewidth >= 0 ? linewidth : getParent().getLineWidth();
	}

	@Override
	public int getLineStyle() {
		init();
		return linetype >= 0 ? linetype : getParent().getLineStyle();
	}

	@Override
	public int getLineSmoothness() {
		init();
		return lineSmoothness >= 0 ? lineSmoothness : getParent().getLineSmoothness();
	}

	@Override
	public int getRoundedBendpointsRadius() {
		init();
		return bendpointRadius >= 0 ? bendpointRadius : getParent().getRoundedBendpointsRadius();
	}

	@Override
	public Class<RotatableDecoration> getTargetDecorator() {
		init();
		return this.targetDecor != null ? this.targetDecor : getParent() != null ? getParent().getTargetDecorator() : null;
	}

	@Override
	public Class<ConnectionLocator> getTargetDecorationLocator() {
		init();
		return this.targetDecorLocator != null ? this.targetDecorLocator : getParent() != null ? getParent().getTargetDecorationLocator() : null;
	}

	@Override
	public Class<RotatableDecoration> getSourceDecorator() {
		init();
		return this.sourceDecor != null ? this.sourceDecor : getParent() != null ? getParent().getSourceDecorator() : null;
	}

	@Override
	public Class<ConnectionLocator> getSourceDecorationLocator() {
		init();
		return this.sourceDecorLocator != null ? this.sourceDecorLocator : getParent() != null ? getParent().getSourceDecorationLocator() : null;
	}

	@Override
	public IBorderEx getBorderEx() {
		if (getBorder() instanceof IBorderEx)
			return (IBorderEx) getBorder();
		return null;
	}

	@Override
	public String getId() {
		return getName();
	}

	@Override
	public String getText() {
		return getName();
	}

	@Override
	public int getObjectType() {
		return LANGUAGE_THEME;
	}
}
